package tp.pr5;

//import tp.pr3.instructions.exceptions.InstructionExecutionException;
import tp.pr5.instructions.exceptions.InstructionExecutionException;
import tp.pr5.items.*;

public class NavigationModule extends Observable<NavigationObserver>{
	private City aCity;	
	private Place currentPlace;	
	private Direction direction;
	
	
	
	/**
	 * Parametrized constructor
	 * @param aCity
	 * @param initialPlace
	 */
	public NavigationModule(City aCity, Place initialPlace){
		this.currentPlace = initialPlace;
		this.aCity = aCity;

	}	
	/**
	 * Returns true if the current place is the spaceship
	 * @return
	 */
	public boolean atSpaceship(){
		return this.currentPlace.isSpaceship();
	}
	/**
	 * sets the initial heading direction
	 * @param heading
	 */
	public void initHeading(Direction heading){
		this.direction = heading;
	}
	/**
	 * rotates the robot to the direction given
	 * @param rotation
	 */
	public void rotate(Rotation rotation){		
		if(rotation.equals(Rotation.LEFT)){//a la izquierda
			this.direction = this.direction.getLeft();							
		}else if(rotation.equals(Rotation.RIGHT)){//a la derecha
			this.direction = this.direction.getRight();						
		}
	}
	/**
	 * returns the current heading direction
	 * @return
	 */
	public Direction getCurrentHeading(){
		return this.direction;
	}
	/**
	 * returns the current place
	 * @return
	 */
	public Place getCurrentPlace(){
		return this.currentPlace;
	}
	/**
	 * sets the current place for the robot
	 * @param pl
	 */
	public void setCurrentPlace(Place pl){
		this.currentPlace = pl;
	}
	/**
	 * drops an item @ the current place
	 * @param it
	 */
	public void dropItemAtCurrentPlace(Item it){
		this.getCurrentPlace().dropItem(it);
		/*
		 * Communicates with the observers
		 */
		for(NavigationObserver no: this.lista){
			no.placeHasChanged(this.getCurrentPlace());
		}
	}
	/**
	 * returns an item with the given id if it exists in the current place
	 * @param id
	 * @return
	 */
	public Item pickItemFromCurrentPlace(String id){
		if(this.currentPlace.getInventory().containsItem(id)){
			return this.currentPlace.getInventory().pickItem(id);
		}else{
			return null;
		}
	}
	/**
	 * moves the robot to the nextplace if possible
	 * @throws InstructionExecutionException
	 */
	public void move() throws InstructionExecutionException{	
		
			Street nxtst = this.aCity.lookForStreet(this.currentPlace, this.direction);
			if(nxtst != null){
				if(!nxtst.isOpen()){
					throw new InstructionExecutionException();
				}
				Place nxtplc = nxtst.nextPlace(this.getCurrentPlace());
				if(nxtplc != null){
					this.setCurrentPlace(nxtplc);//cambia el lugar actual por el siguiente
					
					this.emitArrivedAtPlace();
				}else{
					throw new InstructionExecutionException();
				}
			}else{
				throw new InstructionExecutionException();
			}
		
	}
	/**
	 * @return the aCity
	 */
	public City getaCity() {
		return aCity;
	}
	/**
	 * returns the street the robot is heading to
	 * @return
	 */
	public Street getHeadingStreet() {
		return this.aCity.lookForStreet(this.currentPlace, this.direction);
	}	
	/**
	 * Muestra la situaciÃ³n actual de WALLÂ·E
	 */
	public String showLocation(){
		return showPlaceInfo(this.getCurrentPlace());
	}
	
	public String showPlaceInfo(Place pl){
		String ret = pl.toString();
		
		return ret;
	}
	
	/**
	 * Returns current direction of the robot on a string
	 */
	public String showDirection(){
		return "WALL·E is looking at direction "+this.getCurrentHeading().name();
		
	}
	/**
	 * sets the direction
	 * @param dir
	 */
	public void setDirection(Direction dir){
		this.direction = dir;
	}
	/**
	 * Provides the observers with the information (description + inventory) of the current place
	 */
	public void 	scanCurrentPlace(){	
		//OJO, quitado porque el validador no lo incluye
		for(NavigationObserver no: this.lista){
			no.placeScanned(this.getCurrentPlace());
		}
		
	}
	/**
	 * Informs the observers that the robot has arrived to a place
	 */
	public void emitArrivedAtPlace() {
		for(NavigationObserver no : this.lista)
			no.robotArrivesAtPlace(this.getCurrentHeading(),this.getCurrentPlace());
	}
	/**
	 * Informs the observers that the robot has arrived to a place
	 */
	public void emitNavigationModuleInitialised() {
		for(NavigationObserver no : this.lista)
			no.initNavigationModule(this.getCurrentPlace(), this.getCurrentHeading());			
	}	
	public void emitHeadingChanged() {
		for(NavigationObserver no : this.lista)
			no.headingChanged(this.getCurrentHeading());	
	}
	public void emitUnVisitPlace(Place lastPlace) {
		for(NavigationObserver no : this.lista)
			no.unVisitPlace(lastPlace);
		
	}
	
}
